package sy.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Properties;
import java.util.Date;
import java.util.Calendar;

/**
 * 提供跟日期时间相关的API
 * @author niechen
 *
 */
public class DateTimeUtility {
	
	private static int startWorkHour = 9; //工作日上班时间（几点）
	private static int startWorkMinute = 30; //工作日上班时间(几分）
	private static int endWorkHour = 17; //工作日下班时间（几点）
	private static int endWorkMinute = 30; //工作日下班时间（几分）
	private static long workingDayMilliseconds = 
		((endWorkHour - startWorkHour) * 60 + (endWorkMinute - startWorkMinute)) * 60 * 1000L; //工作日上班时长（毫秒）
	
	private static long moreMilliseconds = 10000L; //给用户的宽限毫秒数，因为用户在界面点击后传到后台有延迟，目前给10秒
	private static String dateTimeFormat = "yyyy-MM-dd HH:mm:ss";
	
	//得到非正常的工作日、节假日信息
	private static Properties prop = new Properties();
	static {
		try {
		    prop.load(DateTimeUtility.class.getResourceAsStream("workingday.properties"));
		} catch(Exception e) {
			e.printStackTrace();
			System.out.println("获取非正常工作日节假日配置文件失败！");
		}
	}
	
	//判断某天是否为工作日
    private static boolean isWorkingDay(Calendar cal) {
    	boolean result;
    	int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
    	//System.out.println("dayOfWeek is " + dayOfWeek);
    	String ymd = formateCalendar(cal, "yyyyMMdd");
    	//System.out.println(ymd);
    	//System.out.println("value is " + prop.getProperty(ymd) + "!");
    	//如果是常规周末，判断是否为特殊工作日
    	if(dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY) {
    		//为工作日，返回true
    		if("1".equals(prop.getProperty(ymd))) {
    			result = true;
    		} else {
    			result = false;
    		}
    	} else { //如果是常规工作日，判断是否为节假日
    		//若果为节假日，返回false
    		if("0".equals(prop.getProperty(ymd))) {
    			result = false;
    		} else {
    			result = true;
    		}
    	}
    	//System.out.println("isWorkingDay: " + result);
    	return result;
    }
    
    private static String formateCalendar(Calendar cal, String format) {
    	SimpleDateFormat sdf = new SimpleDateFormat(format);
    	String result = sdf.format(cal.getTime());
    	//System.out.println("formateCalendar:" + result);
    	return result;
    }
    
    //得到当前时间
    private static Date getCurrent() {
    	Date now = new Date();
    	//给出宽限时间
    	now.setTime(now.getTime() - moreMilliseconds);
    	return now;
    }
    
    /**
     * 判断给定的时间距离当前时间是否大于等于给定的天数
     * @param targetDatetimeStr String 给定的时间，格式为"yyyy-MM-dd HH:mm:ss"
     * @param X int 给定的天数
     * @return boolean 大于等于返回true,否则返回false
     */
    public static boolean isXDaysEarlier(String targetDatetimeStr, int X) throws Exception {
    	Date now = getCurrent();
    	Date targetDate = null;
    	SimpleDateFormat sdf = new SimpleDateFormat(dateTimeFormat);
    	try {
    	    targetDate = sdf.parse(targetDatetimeStr);
    	} catch(Exception e) {
    		e.printStackTrace();
    		throw new Exception("无效的日期时间：" + targetDatetimeStr + "，正确格式为yyyy-MM-dd HH:mm:ss！");
    	}
    	//System.out.println(targetDate.getTime() - now.getTime());
    	boolean result = (targetDate.getTime() - now.getTime()) >= X * 86400000L;
    	System.out.println("isXDaysEarlier(" + targetDatetimeStr + "," + X + ")-" + result);
    	return result;
    }
    
    /**
     * 判断给定的时间距离当前时间是否大于等于给定的工作日数
     * @param targetDatetimeStr String 给定的时间，格式为"yyyy-MM-dd HH:mm:ss"
     * @param X int 给定的工作日数
     * @return boolean 大于等于返回true,否则返回false
     */
    public static boolean isXWorkingDaysEarlier(String targetDatetimeStr, int X) throws Exception {
    	//得到当前日期时间
    	Calendar now = Calendar.getInstance();
    	now.setTime(getCurrent());
    	//得到给定的日期时间
    	Date targetDate = null;
    	SimpleDateFormat sdf = new SimpleDateFormat(dateTimeFormat);
    	try {
    	    targetDate = sdf.parse(targetDatetimeStr);
    	} catch(Exception e) {
    		e.printStackTrace();
    		throw new Exception("无效的日期时间：" + targetDatetimeStr + "，正确格式为yyyy-MM-dd HH:mm:ss！");
    	}
    	Calendar target = Calendar.getInstance();
    	target.setTime(targetDate);
    	
    	//相差的工作日毫秒数
    	long diffMilliseconds = 0;
    	//System.out.println("工作日时长（毫秒）：" + workingDayMilliseconds);
    	Calendar temp = Calendar.getInstance();
    	while(now.before(target)) { //循环直到now晚于或等于target
    		if(isWorkingDay(now)) {  //如果当天是工作日
    			if(!isAfterWorkTime(now)) {  //如果now不晚于下班时间
    			    if(isBeforeWorkTime(now)) { //如果早于上班时间，将now设为当天上班时间
    			    	setToStartWorkTime(now);
    			    }
    			    if(isSameDay(now, target)) { //如果now和target来到了同一天
    			    	if(isBeforeWorkTime(target)) {
    			    		setToStartWorkTime(target);
    			    	} else if(isAfterWorkTime(target)) {
    			    		setToEndWorkTime(target);
    			    	}
    			    	temp.setTime(target.getTime()); //temp设为target时间
    			    } else { //如果没有来到同一天
    			    	//temp设为当天下班时间
    			    	temp.setTime(now.getTime()); 
    			    	setToEndWorkTime(temp);
    			    }
    			    //计算这一天工作日时长（毫秒数）
    			    diffMilliseconds += (temp.getTimeInMillis() - now.getTimeInMillis());
    			    //System.out.println("added to: " + diffMilliseconds);
    			    if(diffMilliseconds >= X * workingDayMilliseconds) { //如果已经可以判断为true，直接返回
    			    	System.out.println("isXWorkingDaysEarlier(" + targetDatetimeStr + "," + X + ")-true");
    			    	return true;
    			    }
    			} 			
    		}
    		//将now设为第二天上班时间，循环到下一天
    		setToNextDayStartWorkTime(now);
    	}
    	boolean result = diffMilliseconds >= X * workingDayMilliseconds;
    	System.out.println("isXWorkingDaysEarlier(" + targetDatetimeStr + "," + X + ")-" + result);
    	return result;
    }
    
    //是否在上班时间前
    private static boolean isBeforeWorkTime(Calendar cal) {
    	int hour = cal.get(Calendar.HOUR_OF_DAY);
    	int minute = cal.get(Calendar.MINUTE);
    	boolean result = hour < startWorkHour || (hour == startWorkHour && minute < startWorkMinute);
    	//System.out.println("isBeforeWorkTime:" + result);
    	return result;
    }
    
  //是否在上班时间后
    private static boolean isAfterWorkTime(Calendar cal) {
    	int hour = cal.get(Calendar.HOUR_OF_DAY);
    	int minute = cal.get(Calendar.MINUTE);
    	boolean result = hour > endWorkHour || (hour == endWorkHour && minute >= endWorkMinute);
    	//System.out.println("isAfterWorkTime:" + result);
    	return result;
    }
    
    //将时间设为第二天的上班时间
    private static void setToNextDayStartWorkTime(Calendar cal) {
    	cal.add(Calendar.DAY_OF_YEAR, 1);
    	setToStartWorkTime(cal);
    	//System.out.println("setToNextDayStartWorkTime:" + cal);
    }
    
    //将时间设为当天上班时间
    private static void setToStartWorkTime(Calendar cal) {
    	cal.set(Calendar.HOUR_OF_DAY, startWorkHour);
    	cal.set(Calendar.MINUTE, startWorkMinute);
    	cal.set(Calendar.SECOND, 0);
    	cal.set(Calendar.MILLISECOND, 0);
    	//System.out.println("setToStartWorkTime:" + cal);
    }
    
  //将时间设为当天下班时间
    private static void setToEndWorkTime(Calendar cal) {
    	cal.set(Calendar.HOUR_OF_DAY, endWorkHour);
    	cal.set(Calendar.MINUTE, endWorkMinute);
    	cal.set(Calendar.SECOND, 0);
    	cal.set(Calendar.MILLISECOND, 0);
    	//System.out.println("setToEndWorkTime:" + cal);
    }
    
    //是否为同一天
    private static boolean isSameDay(Calendar day1, Calendar day2) {
    	boolean result = day1.get(Calendar.YEAR) == day2.get(Calendar.YEAR) && 
    			         day1.get(Calendar.MONTH) == day2.get(Calendar.MONTH) && 
    			         day1.get(Calendar.DAY_OF_MONTH) == day2.get(Calendar.DAY_OF_MONTH);
    	//System.out.println("isSameDay: " + result);
    	return result;
    }
    
    public static void main(String[] args) throws Exception {
    	System.out.println(isXWorkingDaysEarlier("2016-04-18 17:04:00", 3));
    	System.out.println(isXDaysEarlier("2016-04-18 18:04:00", 30));
    }
    
    public static String getCurrentDate() {
    	Date now = new Date(); 
    	SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return dateFormat.format( now ); 
    }
    
    public static String getCurrentDate(String format) {
    	Date now = new Date(); 
    	SimpleDateFormat dateFormat = new SimpleDateFormat(format);
        return dateFormat.format( now ); 
    }
    
    //得到两个时间相差的秒数，时间格式为"yyyy-MM-dd HH:mm:ss"
    public static long getBetweenSeconds(String startTime, String endTime) throws Exception {
    	try {
	    	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	        Calendar cal = Calendar.getInstance();
	        cal.setTime(sdf.parse(startTime));
	        long time1 = cal.getTimeInMillis();     
	        cal.setTime(sdf.parse(endTime)); 
	        long time2 = cal.getTimeInMillis();
	        return (time2 - time1) / 1000;
        } catch(ParseException e) {
        	throw new Exception("日期格式错误！");
        }
    }
}
